﻿using FlickrNet;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using WindowsLive.Writer.Api;

namespace FlickrHarmony {
	public partial class InsertImageForm : Form {
		const string _homeUrl = "http://www.flickr.com/";

		public class SizeItem {
			public ImageSize Value { get; set; }
			public string Name { get; set; }
			public SizeItem(ImageSize value, string name) { this.Value = value; this.Name = name; }
		}

		public InsertImageForm() {
			this.InitializeComponent();
			if (string.IsNullOrEmpty(Plugin.Profile.ImagePattern)) {
				Plugin.Profile.ImagePattern = "<p>x</p>" + Environment.NewLine + "<div class='photo'><img alt='{title}' src='{url}'/></div>";
			}
			ShowThumbnailsBox.Checked = Plugin.Profile.ShowThumbnails;
			txtPattern.Text = Plugin.Profile.ImagePattern;
			ImageList.Columns[0].Width = (ImageList.Width - ImageList.Columns[1].Width) - 10;

			SizeLize.Items.Add(new SizeItem(ImageSize.Medium500, "500 pixels wide"));
			SizeLize.Items.Add(new SizeItem(ImageSize.Medium640, "640 pixels wide"));
			SizeLize.Items.Add(new SizeItem(ImageSize.Large1024, "1024 pixels wide"));
			SizeLize.Items.Add(new SizeItem(ImageSize.Original, "Full size"));
			SizeLize.ValueMember = "Value";
			SizeLize.DisplayMember = "Name";
			SizeLize.SetSelected(Plugin.Profile.ImageSize);

			this.LoadControlsEnabled = false;
			this.ShowStatus("Loading photo sets");
			this.DoWork(this.LoadSetsWorker);
		}

		#region Properties

		/// <summary>
		/// Photos selected for insertion
		/// </summary>
		internal List<Photo> Photos { get; set; }

		/// <summary>
		/// HTML format for inserting images
		/// </summary>
		internal string HtmlFormat { get; set; }

		/// <summary>
		/// Size of images to insert
		/// </summary>
		internal ImageSize ImageSize { get; set; }

		bool LoadControlsEnabled {
			set { ShowThumbnailsBox.Enabled = btnLoad.Enabled = InsertButton.Enabled = SetList.Enabled = value; }
		}

		#endregion

		#region Progress Bar

		void ShowStatus(string message, ProgressBarStyle style) {
			this.RunInMainThread(() => {
				barProgress.Style = style;
				this.ShowStatus(message);
			});
		}

		void ShowStatus(string message) {
			this.RunInMainThread(() => {
				barProgress.Value = 0;
				barProgress.Visible = true;
				lblStatus.Text = message + " …";
			});
		}
		void ClearStatus() {
			this.RunInMainThread(() => {
				barProgress.Visible = false;
				lblStatus.Text = string.Empty;
			});
		}

		ProgressBarStyle ProgressStyle {
			set {
				this.RunInMainThread(() => {
					this.barProgress.Style = value;
					this.barProgress.Value = 0;
					this.barProgress.Visible = (value == ProgressBarStyle.Marquee);
				});
			}
		}

		#endregion

		#region Events

		/// <summary>
		/// Load the photos for the selected Flickr set
		/// </summary>
		private void btnLoad_Click(object sender, EventArgs e) {
			this.LoadControlsEnabled = false;
			this.ProgressStyle = ProgressBarStyle.Continuous;
			ImageList.BeginUpdate();
			ImageList.View = (ShowThumbnailsBox.Checked) ? View.LargeIcon : View.Details;
			this.ShowStatus("Retrieving Photo Information", ProgressBarStyle.Marquee);
			this.DoWork(this.LoadPhotosWorker);
		}

		private void cbxShowThumbnails_CheckedChanged(object sender, EventArgs e) {
			Plugin.Profile.ShowThumbnails = ShowThumbnailsBox.Checked;
			if (ShowThumbnailsBox.Checked) {
				ImageList.View = View.LargeIcon;

				if (ImageList.Items.Count > 0) {
					// update already retrieved images with thumbnails
					this.ProgressStyle = ProgressBarStyle.Continuous;
					this.DoWork(this.LoadThumbnailsWorker);
				}
			} else {
				// view as list if there are no thumbnails
				ImageList.View = View.Details;
			}
		}

		/// <summary>
		/// Cancel work and close the dialog
		/// </summary>
		private void btnCancel_Click(object sender, EventArgs e) {
			if (this.LoadPhotosWorker.IsBusy) { this.LoadPhotosWorker.CancelAsync(); }
			if (this.LoadSetsWorker.IsBusy) { this.LoadSetsWorker.CancelAsync(); }
			base.DialogResult = DialogResult.Cancel;
		}

		/// <summary>
		/// Insert selected images into the blog post
		/// </summary>
		private void btnInsert_Click(object sender, EventArgs e) {
			if (ShowThumbnailsBox.Checked) {
				if (ImageList.SelectedIndices.Count == 0) {
					MessageBox.Show(
						"No photos selected. Please choose at least one photo or cancel to continue.",
						"No photos selected", MessageBoxButtons.OK, MessageBoxIcon.Warning);
					return;
				}
				this.Photos = new List<Photo>();
				foreach (ListViewItem p in ImageList.SelectedItems) { this.Photos.Add((Photo)p.Tag); }
			}
			Plugin.Profile.ImageSize = this.ImageSize = ((SizeItem)SizeLize.SelectedItem).Value;
			this.HtmlFormat = txtPattern.Text;
			base.DialogResult = DialogResult.OK;
		}

		private void flickrLogo_Click(object sender, EventArgs e) { this.GotoUrl(_homeUrl); }

		private void txtPattern_TextChanged(object sender, EventArgs e) {
			Plugin.Profile.ImagePattern = txtPattern.Text;
		}

		#endregion

		#region Background Threads

		/// <summary>
		/// Load complete list of Flickr sets
		/// </summary>
		void LoadSetsWorker_DoWork(object sender, DoWorkEventArgs e) {
			var sets = Plugin.Flickr.PhotosetsGetList(Plugin.Profile.UserID);
			this.RunInMainThread(() => {
				this.LoadControlsEnabled = false;
				InsertButton.Enabled = false;
				SetList.Enabled = true;
				SetList.DataSource = sets;
				SetList.ValueMember = "PhotosetId";
				SetList.DisplayMember = "Title";
			});
		}

		void LoadSetsWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
			this.LoadControlsEnabled = true;
			this.ClearStatus();
			InsertButton.Enabled = !ShowThumbnailsBox.Checked;
		}

		/// <summary>
		/// Load photos for the given Flickr set
		/// </summary>
		void LoadPhotosWorker_DoWork(object sender, DoWorkEventArgs e) {
			string key = DateTime.MinValue.ToLongDateString();
			ListViewItem item;
			var groups = new List<ListViewGroup>();
			string setID = this.ValueFromMainThread(() => (string)SetList.SelectedValue);
			this.Photos = new List<Photo>();
			this.Photos.AddRange(Plugin.Flickr.PhotosetsGetPhotos(setID, PhotoSearchExtras.DateTaken, 1, 200));
			int total = this.Photos.Count;
			int i = 0;

			this.Photos.Sort((p1, p2) => p1.DateTaken.CompareTo(p2.DateTaken));

			// build display groups (grouped by day)
			this.Photos.ForEach(p => {
				if (p.GroupKey() != key) {
					key = p.GroupKey();
					groups.Add(new ListViewGroup(key, key) { Tag = p.DateTaken.StartOfDay() });
				}
			});
			this.RunInMainThread(() => ImageList.Groups.AddRange(groups.ToArray()));

			this.ShowStatus("Parsing Photo Information", ProgressBarStyle.Continuous);

			foreach (var p in this.Photos) {
				if (this.LoadPhotosWorker.CancellationPending) { break; }
				this.RunInMainThread(() => {
					item = new ListViewItem() {
						Name = p.Name(),
						Tag = p,
						Text = p.Name(),
						Selected = true,
						Group = ImageList.Groups[p.GroupKey()],
					};
					item.SubItems.Add(p.DateTaken.ToLongTimeString());
					ImageList.Items.Add(item);
				});
				i++;
				this.LoadPhotosWorker.ReportProgress(i, total);
			}
		}

		/// <summary>
		///  Finished loading photo information
		/// </summary>
		void LoadPhotosWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
			ImageList.EndUpdate();
			ImageList.Focus();
			this.ClearStatus();

			if (ShowThumbnailsBox.Checked) {
				this.LoadThumbnailsWorker.RunWorkerAsync();
			} else {
				this.LoadControlsEnabled = true;
			}
		}

		void ProgressChanged(object sender, ProgressChangedEventArgs e) {
			this.barProgress.Value = e.ProgressPercentage;
		}

		/// <summary>
		/// Load thumbnails for photos
		/// </summary>
		private void LoadThumbnailsWorker_DoWork(object sender, DoWorkEventArgs e) {
			int total = this.Photos.Count;
			MemoryStream stream;
			int i = 0;

			this.RunInMainThread(() => {
				imageList.Images.Clear();
				ImageList.View = View.LargeIcon;
				this.ShowStatus("Loading Thumbnails", ProgressBarStyle.Continuous);
			});

			foreach (var p in this.Photos) {
				if (LoadThumbnailsWorker.CancellationPending) { break; }
				stream = p.ToStream(ImageSize.SmallSquare75);
				this.RunInMainThread(() => {
					imageList.Images.Add(System.Drawing.Image.FromStream(stream));
					ImageList.Items[p.Name()].ImageIndex = i;
				});
				i++;
				LoadThumbnailsWorker.ReportProgress(i, total);
			}
		}

		void LoadThumbnailsWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
			this.ClearStatus();
			this.LoadControlsEnabled = true;
		}

		#endregion

		/// <summary>
		/// Launch default handler (browser) for a URL
		/// </summary>
		void GotoUrl(string url) {
			try {
				System.Diagnostics.Process.Start(url);
			} catch (Exception ex) {
				PluginDiagnostics.DisplayUnexpectedException(ex);
			}
		}
	}
}